﻿using Coway.Ordering.Buyers;
using Coway.Ordering.Orders;
using Coway.Ordering.PayOrders;
using Coway.Ordering.Sellers;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Pdf;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Spire.Pdf;
using Spire.Pdf.Fields;
using Spire.Pdf.Graphics;
using Spire.Pdf.Widget;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Emailing;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.Security.Encryption;
using Volo.Abp.TextTemplating;

namespace Coway.Ordering.Pdfs
{
    /// <summary>
    /// Pdf导出的应用服务
    /// </summary>
    public class PdfAppService : OrderingAppService, IPdfAppService
    {
        private readonly IOrderManager _orderManager;
        private readonly IPdfExporter _pdfExporter;
        private readonly IExcelExporter _excelExporter;
        private readonly IBlobContainer _blobContainer;
        private readonly IRepository<Buyer, Guid> _buyerRepository;
        private readonly IRepository<InstallationInfo, Guid> _installRepository;
        private readonly IRepository<Seller, string> _sellerGenerator;
        private readonly IRepository<ACHPayOrder, Guid> _achPayOrderRepository;
        private readonly IRepository<CCRPayOrder, Guid> _ccrPayOrderRepository;
        private readonly IEmailSender _emailSender;
        private readonly ITemplateRenderer _templateRenderer;
        private readonly IConfiguration _config;
        private readonly IStringEncryptionService _stringEncryptionService;
        private readonly PDFFormHelper _pdfFormHelper;
        protected IEmailSenderConfiguration Configuration { get; }

        public PdfAppService(
            IOrderManager orderManager,
            IPdfExporter pdfExporter,
            IExcelExporter excelExporter,
            IRepository<Buyer, Guid> buyerRepository,
            IRepository<InstallationInfo, Guid> installRepository,
            IRepository<Seller, string> sellerGenerator,
            IRepository<ACHPayOrder, Guid> achPayOrderRepository,
            IRepository<CCRPayOrder, Guid> ccrPayOrderRepository,
            IEmailSender emailSender,
            IConfiguration config,
            ITemplateRenderer templateRenderer,
            IEmailSenderConfiguration configuration,
            IStringEncryptionService stringEncryptionService,
            PDFFormHelper pdfFormHelper,
            IBlobContainer blobContainer)
        {
            _orderManager = orderManager;
            _pdfExporter = pdfExporter;
            _excelExporter = excelExporter;
            _blobContainer = blobContainer;
            _sellerGenerator = sellerGenerator;
            _buyerRepository = buyerRepository;
            _installRepository = installRepository;
            _emailSender = emailSender;
            _config = config;
            _templateRenderer = templateRenderer;
            _achPayOrderRepository = achPayOrderRepository;
            _ccrPayOrderRepository = ccrPayOrderRepository;
            _stringEncryptionService = stringEncryptionService;
            _pdfFormHelper = pdfFormHelper;
            Configuration = configuration;
        }

        public async Task<string> ExportOrder(Guid orderId)
        {
            return await ExportOrder(orderId, null, null);
        }

        /// <summary>
        /// 导出订单信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<string> ExportOrder(Guid orderId, ACHPayOrder achPayOrder, CCRPayOrder ccrPayOrder, byte[] signImages = null)
        {
            var tplPath = Path.Combine(Directory.GetCurrentDirectory(), "ExportTemplates",
                "apptemplate.cshtml");
            var tpl = File.ReadAllText(tplPath);

            var order = await _orderManager.GetOrder(orderId);
            var dto = ObjectMapper.Map<Order, ExportOrderDto>(order);

            List<Attachment> attachments = new List<Attachment>();
            var payFileName = $"{Guid.NewGuid()}.pdf";
            if (achPayOrder != null)
            {
                byte[] payImages = null;
                if (!string.IsNullOrWhiteSpace(achPayOrder.PayImage))
                {
                    payImages = await _blobContainer.GetAllBytesOrNullAsync(achPayOrder.PayImage);
                }
                //var fileBytes = await ExportACHPayOrder(achPayOrder, payFileName);
                var fileBytes = _pdfFormHelper.FillACHPayOrder(achPayOrder, dto, signImages, payImages);
                attachments.Add(new Attachment(new MemoryStream(fileBytes), $"ACH_{DateTime.Now.ToString("yyyyMMdd")}.pdf"));
                dto.SignatureImage = achPayOrder.SignatureImage;
            }

            if (ccrPayOrder != null)
            {
                //var fileBytes = await ExportCCRPayOrder(ccrPayOrder, payFileName);
                var fileBytes = _pdfFormHelper.FillCCRPayOrder(ccrPayOrder, signImages);
                attachments.Add(new Attachment(new MemoryStream(fileBytes), $"CCR_{DateTime.Now.ToString("yyyyMMdd")}.pdf"));
                dto.SignatureImage = ccrPayOrder.SignatureImage;
            }
            //var strOrderId = orderId.ToString();
            //var achPayOrder = await _achPayOrderRepository.FindAsync(p => p.OrderId == strOrderId);
            //if (achPayOrder != null)
            //{
            //    dto.SignatureImage = achPayOrder.SignatureImage;
            //}
            //else
            //{
            //    var ccrPayOrder = await _ccrPayOrderRepository.FindAsync(p => p.OrderId == strOrderId);
            //    if (ccrPayOrder != null)
            //    {
            //        dto.SignatureImage = ccrPayOrder.SignatureImage;
            //    }
            //}

            dto.Buyer = await _buyerRepository.GetAsync(b => b.Id == order.BuyerId);
            dto.InstallationInfo = await _installRepository.GetAsync(a => a.Id == order.InstallationInfoId);
            //dto.Buyer.SocialSecurityNumber = _stringEncryptionService.Decrypt(dto.Buyer.SocialSecurityNumber);
            //dto.Buyer.SocialSecurityNumber = dto.Buyer.SocialSecurityNumberFormat();
            var bytes = _pdfFormHelper.FileOrder(dto, signImages);
            //此处使用默认模板导出
            //var bytes = await _pdfExporter.ExportBytesByTemplate(dto, tpl);

            Logger.LogInformation("获取模板");
            var fileName = $"{Guid.NewGuid()}.pdf";
            // 保留 7 天
            await _blobContainer.SaveAsync(fileName, bytes, true);
            Logger.LogInformation("保存本地文件");

            var emailBody = await _templateRenderer.RenderAsync(
                StandardEmailTemplates.Message,
                new
                {
                    message = @"Dear Customers,
</br></br>
Warm greeting from Coway!
</br></br>
Your order has been submitted successful. Our customer service will contact you by phone call to make arrangement to install, if you have any questions please contact your sales specialist.
</br></br>
Have a nice day!
</br></br>
Coway USA China Dept
</br></br>
"
                }
            );
            Logger.LogInformation("解析邮件模板");
           
            // 发送邮件
            var memoryStream = new MemoryStream(bytes);
            attachments.Add(new Attachment(memoryStream, $"Application_{DateTime.Now.ToString("yyyyMMdd")}.pdf"));
            var seller = await _sellerGenerator.GetAsync(s => s.Code == order.SellerCode);
            //await _emailSender.SendAsync(seller.EMail, "新订单", "内容在附件");
            var from = await Configuration.GetDefaultFromAddressAsync();

            Logger.LogInformation("开始发送邮件");
            await SendMailAsync(from, seller.EMail, seller.ManagerEmail, "新订单", emailBody, attachments);
            Logger.LogInformation("结束发送邮件");

            //20210123 ZMM修改，屏蔽发送邮件给客户
            //try
            //{
            //    await SendMailAsync(from, dto.Buyer.EMail, null, "新订单", emailBody, attachments);
            //}
            //catch (Exception ex)
            //{
            //    Logger.LogError(ex, "客户的邮件没有发生成功，客户邮箱为：{0}", dto.Buyer.EMail);
            //}

            // 返回下载模板的地址
            var host = "http://106.15.9.236:40580/pdf/host/default/";
            return host + fileName;
        }

        /// <summary>
        /// 导出支付订单到PDF（一次性付款、分期付款或租赁的支付信息、可以是支票）
        /// </summary>
        /// <param name="orderId">订单号</param>
        /// <returns></returns>
        public async Task<string> ExportCCRPayOrder(Guid id)
        {
            var payOrder = await _ccrPayOrderRepository.GetAsync(id);
            var fileName = $"{Guid.NewGuid()}.pdf";
            await ExportCCRPayOrder(payOrder, fileName);
            return fileName;

        }

        private async Task<byte[]> ExportCCRPayOrder(CCRPayOrder payOrder, string fileName)
        {
            var tplPath = Path.Combine(Directory.GetCurrentDirectory(),
                "ExportTemplates", "pdf.cshtml");
            var tpl = File.ReadAllText(tplPath);

            var dto = ObjectMapper.Map<CCRPayOrder, ExportCCRPayOrderDto>(payOrder);
            dto.CardNo = _stringEncryptionService.Decrypt(dto.CardNo);
            dto.CVV = _stringEncryptionService.Decrypt(dto.CVV);
            var bytes = await _pdfExporter.ExportBytesByTemplate(dto, tpl);
            // 保留 7 天
            await _blobContainer.SaveAsync(fileName, bytes, true);
            return bytes;
        }

        /// <summary>
        /// 导出支付订单到PDF（一次性付款、分期付款或租赁的支付信息、可以是支票）
        /// </summary>
        /// <param name="orderId">订单号</param>
        /// <returns></returns>
        public async Task<string> ExportACHPayOrder(Guid id)
        {
            var payOrder = await _achPayOrderRepository.GetAsync(id);
            var fileName = $"{Guid.NewGuid()}.pdf";
            await ExportACHPayOrder(payOrder, fileName);
            return fileName;
        }

        private async Task<byte[]> ExportACHPayOrder(ACHPayOrder payOrder, string fileName)
        {
            var tplPath = Path.Combine(Directory.GetCurrentDirectory(),
                "ExportTemplates", "pdf2.cshtml");
            var tpl = File.ReadAllText(tplPath);

            var dto = ObjectMapper.Map<ACHPayOrder, ExportACHPayOrderDto>(payOrder);
            dto.CardNo = _stringEncryptionService.Decrypt(dto.CardNo);
            dto.CVV = _stringEncryptionService.Decrypt(dto.CVV);
            var bytes = await _pdfExporter.ExportBytesByTemplate(dto, tpl);

            // 保留 7 天
            await _blobContainer.SaveAsync(fileName, bytes, true);
            return bytes;
        }

        ///// <summary>
        ///// 导出支付订单到PDF（一次性付款、分期付款或租赁的支付信息、可以是支票）
        ///// </summary>
        ///// <param name="orderId">订单号</param>
        ///// <returns></returns>
        //public async Task<string> ExportPayOrder(Guid orderId)
        //{
        //    var tplPath = Path.Combine(Directory.GetCurrentDirectory(),
        //        "ExportTemplates", "pdf2.cshtml");
        //    var tpl = File.ReadAllText(tplPath);

        //    var order = await _orderManager.GetOrder(orderId);
        //    var dto = ObjectMapper.Map<Order, ExportOrderDto>(order);
        //    var strOrderId = orderId.ToString();
        //    var achPayOrder = await _achPayOrderRepository.FindAsync(p => p.OrderId == strOrderId);
        //    if (achPayOrder != null)
        //    {
        //        dto.SignatureImage = achPayOrder.SignatureImage;
        //    }
        //    else
        //    {
        //        var ccrPayOrder = await _ccrPayOrderRepository.FindAsync(p => p.OrderId == strOrderId);
        //        if (ccrPayOrder != null)
        //        {
        //            dto.SignatureImage = ccrPayOrder.SignatureImage;
        //        }
        //    }

        //    dto.Buyer = await _buyerRepository.GetAsync(b => b.Id == order.BuyerId);
        //    dto.InstallationInfo = await _installRepository.GetAsync(a => a.Id == order.InstallationInfoId);

        //    //此处使用默认模板导出
        //    var bytes = await _pdfExporter.ExportBytesByTemplate(dto, tpl);

        //    Logger.LogInformation("获取模板");
        //    var fileName = $"{Guid.NewGuid()}.pdf";
        //    // 保留 7 天
        //    await _blobContainer.SaveAsync(fileName, bytes, true);
        //    Logger.LogInformation("保存本地文件");

        //    var emailBody = await _templateRenderer.RenderAsync(
        //        StandardEmailTemplates.Message,
        //        new
        //        {
        //            message = "新订单，内容在附件中。。。"
        //        }
        //    );
        //    Logger.LogInformation("解析邮件模板");

        //    // 发送邮件
        //    var seller = await _sellerGenerator.GetAsync(s => s.Code == order.SellerCode);
        //    //await _emailSender.SendAsync(seller.EMail, "新订单", "内容在附件");
        //    var from = await Configuration.GetDefaultFromAddressAsync();

        //    Logger.LogInformation("开始发送邮件");
        //    await SendMailAsync(from, seller.EMail, seller.ManagerEmail, "新订单", emailBody, bytes, fileName);
        //    Logger.LogInformation("结束发送邮件");

        //    // 返回下载模板的地址
        //    var host = "http://106.15.9.236:40580/pdf/host/default/";
        //    return host + fileName;
        //}

        /// <summary>
        /// 发送邮件
        /// Gmail发送邮件参考：https://community.abp.io/articles/replacing-email-templates-and-sending-emails-jkeb8zzh
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="cc"></param>
        /// <param name="subject"></param>
        /// <param name="body"></param>
        /// <param name="bytes"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public async Task<bool> SendMailAsync(string from, string to, string cc, string subject, string body, List<Attachment> attachments)
        {
            try
            {
                Logger.LogInformation("发送邮件 ");
                var mailMessage = new MailMessage(from, to, subject, body);
                mailMessage.IsBodyHtml = true;

                if (_config["AllowEmailCC"]?.Equals(bool.TrueString, StringComparison.InvariantCultureIgnoreCase) == true)
                {
                    if (!string.IsNullOrWhiteSpace(cc))
                    {
                        Logger.LogWarning("即将抄送给用户：{0}", cc);
                        mailMessage.CC.Add(cc);
                    }
                }

                mailMessage.Attachments.Clear();

                //Logger.LogInformation("开始读取附件信息");
                //添加邮件附件，可发送多个文件
                foreach (var attachment in attachments)
                {
                    mailMessage.Attachments.Add(attachment);
                }

                Logger.LogInformation("Gmail发送邮件开始");

                /// Gmail发送邮件参考：https://community.abp.io/articles/replacing-email-templates-and-sending-emails-jkeb8zzh
                await _emailSender.SendAsync(mailMessage);
                Logger.LogInformation("Gmail发送邮件结束");

                Logger.LogWarning("邮件成功发送给：{0}", to);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "发送邮件报错,错误原因：" + ex.Message);
                throw ex;
            }
            return true;
        }

        public byte[] FillCCRPayOrder(CCRPayOrder payOrder)
        {
            payOrder.CardNo = _stringEncryptionService.Decrypt(payOrder.CardNo);
            payOrder.CVV = _stringEncryptionService.Decrypt(payOrder.CVV);

            PdfDocument doc = new PdfDocument();
            var tplPath = Path.Combine(Directory.GetCurrentDirectory(),
                "ExportTemplates", "CREDITCARD.pdf");
            doc.LoadFromFile(tplPath);
            PdfFormWidget formWidget = doc.Form as PdfFormWidget;
            for (int i = 0; i < formWidget.FieldsWidget.List.Count; i++)
            {
                PdfField field = formWidget.FieldsWidget.List[i] as PdfField;
                if (field is PdfTextBoxFieldWidget)
                {
                    PdfTextBoxFieldWidget textBoxField = field as PdfTextBoxFieldWidget;
                    switch (textBoxField.Name)
                    {
                        case "CARD":
                            textBoxField.Text = payOrder.CardNo ?? "";
                            break;
                        case "EXPIRATION DATE":
                            textBoxField.Text = payOrder.ExpirationDate.HasValue ? payOrder.ExpirationDate.Value.ToString("MM/dd/yyyy") : "";
                            break;
                        case "CVV":
                            textBoxField.Text = payOrder.CVV ?? "";
                            break;
                        case "CARD HOLDER NAME":
                            textBoxField.Text = payOrder.CardHolderName ?? "";
                            break;
                        case "ORDER ":
                            textBoxField.Text = "";
                            break;
                        case "AMOUNT":
                            textBoxField.Text = payOrder.Amount.HasValue ? payOrder.Amount.Value.ToString() : "";
                            break;
                        case "BILLING ADDRESS":
                            textBoxField.Text = $"{payOrder.BillingAddressState} {payOrder.BillingAddressCity} {payOrder.BillingAddressApt} {payOrder.BillingAddressStreet} {payOrder.BillingAddressZipCode}";
                            break;
                        case "ZIP CODE":
                            textBoxField.Text = payOrder.ZipCode ?? "";
                            break;
                        case "REMARK":
                            textBoxField.Text = payOrder.Remark ?? "";
                            break;
                        case "DATE":
                            textBoxField.Text = payOrder.Date.HasValue ? payOrder.Date.Value.ToString("MM/dd/yyyy") : "";
                            break;
                        case "CONTACT":
                            textBoxField.Text = payOrder.Contact ?? "";
                            break;
                        case "RECEIVER":
                            textBoxField.Text = payOrder.Receiver ?? "";
                            break;
                        case "Signature_es_:signer:signature":

                            //Image image = Image.FromFile(@"logo.png");
                            ////调整图片大小
                            //int width = 100;
                            //int height = 35;
                            //float scale = 0.8f;  //缩放比例
                            //Size size = new Size((int)(width * scale), (int)(height * scale));
                            //Bitmap scaledImage = new Bitmap(image, size);

                            ////加载缩放后的图片到PdfImage对象
                            //PdfImage pdfImage = PdfImage.FromStream(new MemoryStream(Convert.FromBase64String(payOrder.SignatureImage)));

                            //////设置图片位置
                            //float x = 225f;
                            //float y = 573f;
                            //doc.Pages[0].Canvas.DrawImage(pdfImage, x, y);
                            break;
                    }
                }

                if (field is PdfCheckBoxWidgetFieldWidget)
                {
                    PdfCheckBoxWidgetFieldWidget checkBoxField = field as PdfCheckBoxWidgetFieldWidget;
                    switch (checkBoxField.Name)
                    {
                        case "VISA":
                            checkBoxField.Checked = payOrder.CardType == "Visa";
                            break;
                        case "MASTER":
                            checkBoxField.Checked = payOrder.CardType == "MasterCard";
                            break;
                        case "DISCOVER":
                            checkBoxField.Checked = payOrder.CardType == "Discover";
                            break;
                    }
                }
            }

            using (MemoryStream ms = new MemoryStream())
            {
                doc.SaveToStream(ms);
                byte[] buffer = new byte[ms.Length];
                ms.Seek(0, SeekOrigin.Begin);
                ms.Flush();
                ms.Read(buffer, 0, (int)ms.Length);

                return buffer;
            }

            //var memoryStream = new MemoryStream();
            //doc.SaveToStream(memoryStream);
            //return memoryStream;
        }

        public byte[] FillACHPayOrder(ACHPayOrder payOrder)
        {
            payOrder.CardNo = _stringEncryptionService.Decrypt(payOrder.CardNo);
            payOrder.CVV = _stringEncryptionService.Decrypt(payOrder.CVV);

            PdfDocument doc = new PdfDocument();
            var tplPath = Path.Combine(Directory.GetCurrentDirectory(),
                "ExportTemplates", "ACH CCR FORM.pdf");
            doc.LoadFromFile(tplPath);
            PdfFormWidget formWidget = doc.Form as PdfFormWidget;
            for (int i = 0; i < formWidget.FieldsWidget.List.Count; i++)
            {
                PdfField field = formWidget.FieldsWidget.List[i] as PdfField;
                if (field is PdfTextBoxFieldWidget)
                {
                    PdfTextBoxFieldWidget textBoxField = field as PdfTextBoxFieldWidget;
                    switch (textBoxField.Name)
                    {
                        case "Customer Name":
                            textBoxField.Text = payOrder.CustomerName ?? "";
                            break;
                        case "Phone":
                            textBoxField.Text = payOrder.Phone ?? "";
                            break;
                        case "Address":
                            textBoxField.Text = payOrder.Address ?? "";
                            break;
                        case "Card Holder Name":
                            textBoxField.Text = payOrder.CardHolderName ?? "";
                            break;
                        case "Card Number":
                            textBoxField.Text = payOrder.CardNo ?? "";
                            break;
                        case "Expiration Date":
                            textBoxField.Text = payOrder.ExpirationDate.HasValue ? payOrder.ExpirationDate.Value.ToString("MM/dd/yyyy") : "";
                            break;
                        case "Billing Address":
                            textBoxField.Text = $"{payOrder.BillingAddressState} {payOrder.BillingAddressCity} {payOrder.BillingAddressApt} {payOrder.BillingAddressStreet} {payOrder.BillingAddressZipCode}";
                            break;
                        case "CVV#":
                            textBoxField.Text = payOrder.CVV ?? "";
                            break;
                        case "DATE":
                            textBoxField.Text = payOrder.Date.HasValue ? payOrder.Date.Value.ToString("MM/dd/yyyy") : "";
                            break;
                        case "Remark":
                            //需要写中文字段前面增加下面两行

                            Font font = new Font("Microsoft Yahei", 10, FontStyle.Regular);
                            textBoxField.Font = new PdfTrueTypeFont(font, true);
                            textBoxField.Text = "测试是否可以填写";
                            textBoxField.ReadOnly = true;
                            break;
                        case "Signature1_es_:signer:signature":

                            //Image image = Image.FromFile(@"logo.png");
                            ////调整图片大小
                            //int width = 300;
                            //int height = 42;
                            //float scale = 0.8f;  //缩放比例
                            //Size size = new Size((int)(width * scale), (int)(height * scale));
                            //Bitmap scaledImage = new Bitmap(image, size);

                            ////加载缩放后的图片到PdfImage对象
                            //PdfImage pdfImage = PdfImage.FromImage(scaledImage);

                            ////设置图片位置
                            //float x = 141f;
                            //float y = 668f;
                            //doc.Pages[0].Canvas.DrawImage(pdfImage, x, y);
                            break;
                    }
                }

                if (field is PdfCheckBoxWidgetFieldWidget)
                {
                    PdfCheckBoxWidgetFieldWidget checkBoxField = field as PdfCheckBoxWidgetFieldWidget;
                    switch (checkBoxField.Name)
                    {
                        case "10th":
                            checkBoxField.Checked = payOrder.PaymentDate == "10th";
                            break;
                        case "15th":
                            checkBoxField.Checked = payOrder.PaymentDate == "15th";
                            break;
                        case "20th":
                            checkBoxField.Checked = payOrder.PaymentDate == "20th";
                            break;
                        case "Visa":
                            checkBoxField.Checked = payOrder.CardType == "Visa";
                            break;
                        case "Master Card":
                            checkBoxField.Checked = payOrder.CardType == "MasterCard";
                            break;
                        case "Discover":
                            checkBoxField.Checked = payOrder.CardType == "Discover";
                            break;
                    }
                }
            }

            using (MemoryStream ms = new MemoryStream())
            {
                doc.SaveToStream(ms);
                byte[] buffer = new byte[ms.Length];
                ms.Seek(0, SeekOrigin.Begin);
                ms.Flush();
                ms.Read(buffer, 0, (int)ms.Length);

                return buffer;
            }
        }
    }
}
